﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using FinPlusInterfaces;
using FinPlusAssembler;

namespace FinPlusBaseCore
{
    public class PPods : IPPods
    {
        private readonly IPods _pods;
        private class User: Dictionary<string, Name>{ }
        private class Name : Dictionary<string, BeanName> { }
        private class BeanName : Dictionary<string, BeanValue> { }
        private class BeanValue : Dictionary<string, PPod> { }
        private User _index = new User();
        private enum Params { Permission, User, Name, BeanName, BeanValue, CanRead, CanWrite }
        
        //construct
        public PPods(IPods pods)
        {
            _pods = pods;
            _pods.PodUpdate += PPod_Update;

            lock (_pods)
                foreach (var pod in _pods.Values.Where(f => f[PodField.Type.ToString()].Equals(Params.Permission.ToString())))
                    Add(pod);
        }

        //public
        public IPPod Get(string user, string name, string beanName, string beanValue)
        {
            try
            {
                if (_index.ContainsKey(user))
                {
                    var u = _index[user];
                    if (u.ContainsKey(name))
                    {
                        var n = u[name];
                        if (n.ContainsKey(beanName))
                        {
                            var i = n[beanName];
                            if (i.ContainsKey(beanValue))
                                return i[beanValue];
                            else if (i.ContainsKey("*"))
                                return i["*"];
                        }
                    }
                }

                return new PPod(false, false);
            }
            catch
            {
                return new PPod(false, false);
            }
        }

        //private
        private void Add(IPod pod)
        {
            try
            {
                var user = pod[Params.User.ToString()].ToString();
                var name = pod[Params.Name.ToString()].ToString();
                var beanName = pod[Params.BeanName.ToString()].ToString();
                var beanValue = pod[Params.BeanValue.ToString()].ToString();
                var perm = new PPod((bool)pod.Value(Params.CanRead.ToString()), (bool)pod.Value(Params.CanWrite.ToString()), beanValue.Equals("*"));

                if (!_index.ContainsKey(user))
                    _index[user] = new Name();

                if (!_index[user].ContainsKey(name))
                    _index[user][name] = new BeanName();

                if (!_index[user][name].ContainsKey(beanName))
                    _index[user][name][beanName] = new BeanValue();

                _index[user][name][beanName][beanValue] = perm;
            }
            catch (Exception e)
            {
                Level.Debug.Log(string.Format("Permission format error {0}", pod.ToString()), e);
            }
        }

        //event
        private void PPod_Update(object s, BeanEventArgs a)
        {
            try
            {
                var pod = (IPod)s;

                if (!pod[PodField.Type.ToString()].ToString().Equals(Params.Permission.ToString())) 
                    return;
              
                lock (_pods)
                {
                    if (a.ChangeType == ChangeType.Removed)
                        _index[pod[Params.User.ToString()].ToString()][pod[Params.Name.ToString()].ToString()][pod[Params.BeanName.ToString()].ToString()].Remove(pod[Params.BeanValue.ToString()].ToString());
                    else if (a.ChangeType == ChangeType.New || a.ChangeType == ChangeType.Altered)
                        Add(pod);
                }
            }
            catch(Exception e)
            {
                throw new PodException("PPod update format error", e);
            }
        }
    }
}

